﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;

namespace KopytkoService
{
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class MainService : IMainService
    {
        #region Dane zalogowanego usera
        private int? SessionId = null;
        private int? UserId = null;
        private string ClientEndpointAddress;
        #endregion


        public int LogIn(string username, string password)
        {
            var ctx = new KopytkoDbDataContext();

            // czy mamy takiego w bazie?
            User user = (from u in ctx.Users
                         where u.Login == username
                         select u).FirstOrDefault();

            if (user == null)
            {
                ctx.Dispose();
                throw new FaultException<AuthenticationFault>(
                    new AuthenticationFault(AuthenticationFaultReason.InvalidCredentials));
            }

            // czy podał dobre hasło?
            if (user.Pass != password)
            {
                ctx.Dispose();
                throw new FaultException<AuthenticationFault>(
                    new AuthenticationFault(AuthenticationFaultReason.InvalidCredentials));
            }

            // generujemy losowe id sesji dopóki w bazie się takie znajduje
            // (ma być unikalne)
            int session_id;
            var generator = new Random();
            bool is_in_db;
            do
            {
                session_id = generator.Next();
                is_in_db = (from u in ctx.Users
                            where u.SessionId == session_id
                            select true).FirstOrDefault();
            } while (is_in_db);


            
            try
            {
                var clientEndpoint =
                    OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as
                    RemoteEndpointMessageProperty;
                ClientEndpointAddress = clientEndpoint.Address;
            }
            catch
            {
            }


            // odnotowanie eventu zalogowania
            var login_event = new Event()
            {
                UserId = user.Id,
                TypeId = 1,
                Time = DateTime.Now,
                Endpoint = ClientEndpointAddress
            };

            ctx.Events.InsertOnSubmit(login_event);

            SessionId = session_id;
            UserId = user.Id;

            ctx.SubmitChanges();
            ctx.Dispose();

            return session_id;
        }

        public void LogOut(int sessionId)
        {
            CheckSessionId(sessionId);

            var ctx = new KopytkoDbDataContext();

            User user = (from u in ctx.Users
                         where u.SessionId == SessionId
                         select u).FirstOrDefault();

            if (user == null)
            {
                ctx.Dispose();
                return;
            }

           
            // odnotowanie eventu wylogowania
            var logout_event = new Event()
            {
                UserId = user.Id,
                TypeId = 2,
                Time = DateTime.Now,
                Endpoint = ClientEndpointAddress
            };

            ctx.Events.InsertOnSubmit(logout_event);

            ctx.SubmitChanges();
            ctx.Dispose();
        }

        private void CheckSessionId(int sessionId)
        {

            if ((sessionId != SessionId) || (SessionId.HasValue == false))
                throw new FaultException<AuthenticationFault>(
                    new AuthenticationFault(AuthenticationFaultReason.InvalidSessionId));
        }

       
        #region IMainService Members


        public Game[] GetAvailableGames(int sessionId)
        {
            CheckSessionId(sessionId);

            using (var ctx = new KopytkoDbDataContext())
            {
                var ret = from g in ctx.Games
                          select g;

                return ret.ToArray();
            }
        }

        public Game GetGame(int sessionId, int gameId)
        {
            CheckSessionId(sessionId);

            using (var ctx = new KopytkoDbDataContext())
            {
                var ret = (from g in ctx.Games
                          where g.Id == gameId
                          select g).Single();

                ret.MM_User_Games.Add(new MM_User_Game()
                                          {
                                              UserId = UserId.Value
                                          });

                return ret;
            }
        }

        #endregion
    }


    public enum AuthenticationFaultReason
    {
        InvalidCredentials,
        InvalidSessionId,
    }

    [DataContract]
    public class AuthenticationFault
    {
        public AuthenticationFault(AuthenticationFaultReason reason)
        {
            Reason = reason;
        }

        [DataMember]
        public AuthenticationFaultReason Reason { get; private set; }
    }

}
